package com.lu.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lu.mapper.SysResourcesMapper;
import com.lu.mapper.SysRoleMapper;
import com.lu.mapper.SysRoleResourcesMapper;
import com.lu.mapper.SysUserRoleMapper;
import com.lu.model.entity.*;
import com.lu.model.enums.YesOrNoEnum;
import com.lu.model.exception.LuBootAssert;
import com.lu.model.request.RoleQueryRequest;
import com.lu.model.request.RoleResourcesUpdateRequest;
import com.lu.service.SysRoleService;
import com.lu.service.SysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 角色信息表 服务实现类
 * </p>
 *
 * @author wangqieyu
 * @since 2022-07-26
 */
@RequiredArgsConstructor
@Service
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {

  private final SysResourcesMapper resourcesMapper;
  private final SysUserRoleMapper userRoleMapper;
  private final SysRoleResourcesMapper roleResourcesMapper;
  private final SysUserService userService;

  @Override
  public Long addRole(SysRole role) {
    LuBootAssert.isTrue(ObjectUtil.isEmpty(role.getStatus())
        || Arrays.stream(YesOrNoEnum.values()).anyMatch(o -> o.getValue() == role.getStatus()), "无效的状态参数");
    LuBootAssert.isTrue(ObjectUtil.isAllNotEmpty(role.getName()), "请输入角色名称");
    this.checkNameUnique(null, role.getName());
    SysUser loginUser = (SysUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    role.setId(null);
    role.setCreateUserId(loginUser.getId());
    role.setUpdateUserId(loginUser.getId());
    this.baseMapper.insert(role);
    return role.getId();
  }

  @Override
  public SysRole updateRole(SysRole role) {
    LuBootAssert.isTrue(ObjectUtil.isEmpty(role.getStatus())
        || Arrays.stream(YesOrNoEnum.values()).anyMatch(o -> o.getValue() == role.getStatus()), "无效的状态参数");
    LuBootAssert.isTrue(ObjectUtil.isAllNotEmpty(role.getId()), "无效的参数");
    this.checkNameUnique(role.getId(), role.getName());
    SysUser loginUser = (SysUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    role.setUpdateUserId(loginUser.getId());
    role.setUpdateTime(LocalDateTime.now());
    this.baseMapper.updateById(role);
    if(role.getStatus() != null){
      this.updateLoginUser(role.getId());
    }
    return this.baseMapper.selectById(role.getId());
  }

  @Override
  public Integer updateStatus(Long id, Integer status) {
    LuBootAssert.isTrue(Arrays.stream(YesOrNoEnum.values()).anyMatch(o -> o.getValue() == status), "无效的状态参数");
    SysUser loginUser = (SysUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    SysRole updateRole = new SysRole();
    updateRole.setId(id);
    updateRole.setStatus(status);
    updateRole.setUpdateUserId(loginUser.getId());
    updateRole.setUpdateTime(LocalDateTime.now());
    int res = this.baseMapper.updateById(updateRole);
    this.updateLoginUser(id);
    return res;
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public String deleteRole(Long id) {
    //删除角色
    int rs01 = this.baseMapper.deleteById(id);
    //删除用户角色关系
    QueryWrapper<SysUserRole> userRoleQueryWrapper = new QueryWrapper<>();
    userRoleQueryWrapper.eq("role_id", id);
    List<SysUserRole> userRoles = userRoleMapper.selectList(userRoleQueryWrapper);
    int rs02 = 0;
    if(ObjectUtil.isNotEmpty(userRoles)){
      rs02 = userRoleMapper.deleteBatchIds(userRoles.stream().map(SysUserRole::getId).collect(Collectors.toList()));
    }
    //删除角色资源关系
    QueryWrapper<SysRoleResources> resourcesQueryWrapper = new QueryWrapper<>();
    resourcesQueryWrapper.eq("role_id", id);
    int rs03 = roleResourcesMapper.delete(resourcesQueryWrapper);
    this.updateLoginUser(userRoles);
    return rs01 + "-" + rs02 + "-" + rs03;
  }

  @Override
  public Page<SysRole> pageList(RoleQueryRequest request) {
    QueryWrapper<SysRole> roleQueryWrapper = new QueryWrapper<>();
    if(ObjectUtil.isNotEmpty(request.getStatus())){
      roleQueryWrapper.eq("status", request.getStatus());
    }
    if(ObjectUtil.isNotEmpty(request.getName())){
      roleQueryWrapper.like("name", request.getName());
    }
    if(ObjectUtil.isNotEmpty(request.getDescription())){
      roleQueryWrapper.like("description", request.getDescription());
    }
    roleQueryWrapper.orderByDesc("create_time");
    Page<SysRole> rolePage = this.baseMapper.selectPage(new Page<>(request.getPageIndex(), request.getPageSize()), roleQueryWrapper);
    return rolePage;
  }

  @Override
  public List<SysRole> roleList(RoleQueryRequest request) {
    QueryWrapper<SysRole> roleQueryWrapper = new QueryWrapper<>();
    if(ObjectUtil.isNotEmpty(request.getStatus())){
      roleQueryWrapper.eq("status", request.getStatus());
    }
    if(ObjectUtil.isNotEmpty(request.getName())){
      roleQueryWrapper.like("name", request.getName());
    }
    if(ObjectUtil.isNotEmpty(request.getDescription())){
      roleQueryWrapper.like("description", request.getDescription());
    }
    roleQueryWrapper.orderByDesc("create_time");
    List<SysRole> roleList = this.baseMapper.selectList(roleQueryWrapper);
    return roleList;
  }

  @Override
  public String updateResources(RoleResourcesUpdateRequest request) {
    SysUser loginUser = (SysUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    QueryWrapper<SysRoleResources> roleResourcesQueryWrapper = new QueryWrapper<>();
    roleResourcesQueryWrapper.eq("role_id", request.getRoleId());
    int rs01 = roleResourcesMapper.delete(roleResourcesQueryWrapper);
    int rs02 = 0;
    for (Long resourceId : request.getResourceIds()) {
      SysRoleResources roleResources = new SysRoleResources();
      roleResources.setRoleId(request.getRoleId());
      roleResources.setResourceId(resourceId);
      roleResources.setUpdateUserId(loginUser.getId());
      roleResources.setUpdateTime(LocalDateTime.now());
      int rs03 = roleResourcesMapper.insert(roleResources);
      rs02 += rs03;
    }
    this.updateLoginUser(request.getRoleId());
    return rs01 + "-" + rs02;
  }

  @Override
  public SysRole getByRoleId(Long id) {
    SysRole role = this.baseMapper.selectById(id);
    LuBootAssert.isTrue(role != null, "不存在该角色");
    List<SysResources> resourcesList = resourcesMapper.getByRoleId(id);
    role.setResourcesList(resourcesList);
    return role;
  }

  @Override
  public List<SysRole> sort(List<Long> ids) {
    if(ObjectUtil.isEmpty(ids)){
      return null;
    }
    for (int i = 0; i < ids.size(); i++) {
      SysRole role = new SysRole();
      role.setId(ids.get(i));
      role.setSort(i);
      this.baseMapper.updateById(role);
    }
    QueryWrapper<SysRole> roleQueryWrapper = new QueryWrapper<>();
    roleQueryWrapper.in("id", ids);
    return this.baseMapper.selectList(roleQueryWrapper);
  }

  private void checkNameUnique(Long id, String name){
    if(ObjectUtil.isEmpty(name)){
      return;
    }
    QueryWrapper<SysRole> roleQueryWrapper = new QueryWrapper<>();
    roleQueryWrapper.eq("name", name);
    if(ObjectUtil.isNotEmpty(id)){
      roleQueryWrapper.ne("id", id);
    }
    Integer count = this.baseMapper.selectCount(roleQueryWrapper);
    LuBootAssert.isTrue(count == 0, "角色名称不能重复");
  }

  public void updateLoginUser(Long roleId){
    QueryWrapper<SysUserRole> userRoleQueryWrapper = new QueryWrapper<>();
    userRoleQueryWrapper.eq("role_id", roleId);
    List<SysUserRole> userRoles = userRoleMapper.selectList(userRoleQueryWrapper);
    this.updateLoginUser(userRoles);
  }

  public void updateLoginUser(List<SysUserRole> userRoles){
    if(ObjectUtil.isEmpty(userRoles)){
      return;
    }
    for (SysUserRole userRole : userRoles) {
      userService.updateLoginUser(userRole.getUserId());
    }
  }

}
